﻿// Copyright: 北京经海科技有限公司
// Author: Ivan (李渊)
// Date: 2015-03-01
// Last Modified On: 2015-05-22
// Description: 辅助类，用于给图像增加标注

#ifndef DRAW_SHAPE_H
#define DRAW_SHAPE_H

#include <QObject>
#include <QPointF>
#include <QPainter>
#include <QFont>
#include <QPen>
#include <QColor>
#include <QStaticText>
#include "MeasureAlgorithm.h"
#include "TextBlock.h"

namespace Qly
{
class DisplayWidget;

//绘图命令
class Element : public QObject
{
public:
    enum DrawType{ NONE, LINE, CALIB_LINE, CORNER, LINECORNER, PARALLEL_AUTO, PARALLEL, RCIRCLE, LCIRCLE, CIRCLE2CIRCLE, ARC, PCIRCLE, CURVE, POLYGON, RECTAGLE, POLYLINE, HTLINE, VTLINE, TEXT, DOTSTOLINE };
    enum DrawState {DS_IDLE, DS_STATE1, DS_STATE2, DS_STATE3, DS_FINISH, DS_ERROR};
    Element();
    virtual ~Element() {}
    void setLinePen(QPen &pen) {m_linePen = pen; m_textBlock.setPen(pen);}
    void setTextFont(QFont &font) {m_textFont = font; m_textBlock.setFont(font);}
    static double scale();
    void textMove(const QPointF & offset){ m_textBlock.translate(offset.toPoint());}
    virtual int mouseLButtonPress(QPointF point) = 0;
    virtual int mouseLButtonRelease(QPointF point) {Q_UNUSED(point); return 0;}
    virtual int mouseRButtonPress(QPointF point) {Q_UNUSED(point); return 0;}
    virtual int mouseMove(QPointF point) {Q_UNUSED(point); return 0;}
    virtual void draw( QPainter &painter ) = 0; //画方法
    virtual void updateText(void) {}
    enum DrawState state() const {return m_state;}
    enum DrawType type() const {return m_drawType;}
    bool isInTextBox(const QPointF & point) {return m_textBlock.contains(point.toPoint());}
protected:	
    void updateTextPos();
protected:
    enum DrawType m_drawType;//图形样式
    enum DrawState m_state; // 元素是否绘制结束
    QPen m_linePen;//线的颜色
    bool m_isPicked; // 判断是否被选择
    QString m_text;
    QFont m_textFont;  //文字的字体
    TextBlock m_textBlock;
    //static double m_zoomFactor; // DisplayWidget 放缩时标注也要相应的放缩，但是文字大小不变
};

class DrawLine:public Element
{
public:
    DrawLine(void);
    ~DrawLine(void) {}
    void setBarLength(int len){BAR_LEN = len;}
    void build(QPointF start, QPointF end);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    bool adjust(QPointF p);
    double getLength() {return m_length;}
    bool moveState(QPointF point);
    void cancelMoveState() {m_adjust = 0;}
protected:
    double BAR_LEN; // 直线标记两边小线段的长度
    QPointF m_points[2];

    //为了出现标尺的图形，还得加上四个标尺的坐标
    QPointF m_line1_start;
    QPointF m_line1_end;
    QPointF m_line2_start;
    QPointF m_line2_end;

    double m_length;//标尺的长度，以像素为单位
    double m_cos_theta;
    double m_sin_theta;
    int m_adjust;
    QPointF m_tempPoint;

    void setStartPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setEndPoint(QPointF point);
    void compute(void);
    void computeLength(void); // 得到线段的长度
};

class DrawPolyline:public Element
{
public:
    DrawPolyline(void);
    ~DrawPolyline(void) {}
    void build(QVector<QPointF> points);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseRButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getLength() {return m_length;}
private:
    QVector<QPointF> m_points; // 开始点
    QPointF m_tempEnd;
    double m_length;//标尺的长度，以像素为单位
private:
    void setStartPoint(QPointF point);
    void setMidPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setEndPoint(QPointF point);
    void compute(void);
    void computeLength(void); // 得到线段的长度
};


class CalibLine: public DrawLine
{
public:
    CalibLine();
    ~CalibLine() {}
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
private:
    void setEndPoint(QPointF point);
};

class DrawPolygon:public Element
{
public:
    DrawPolygon(void);
    ~DrawPolygon(void) {}
    void build(QVector<QPointF> points);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseRButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getArea() {return m_area;}
private:
    QVector<QPointF> m_points; // 开始点
    QPointF m_tempEnd;
    double m_area;//区域的面积，以像素为单位
private:
    void setStartPoint(QPointF point);
    void setMidPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setEndPoint(QPointF point);
    void compute(void);
};

class HTLine:public DrawLine
{
public:
    HTLine(void);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF) Q_DECL_OVERRIDE;
    static void setHLine(int hline) {m_hline = hline;}
private:
    static int m_hline;
};
class VTLine:public DrawLine
{
public:
    VTLine(void);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    static void setVLine(int vline) {m_vline = vline;}
private:
    static int m_vline;
};

class DrawParallelLineAuto: public DrawLine
{
public:
    DrawParallelLineAuto(DisplayWidget * dw) : DrawLine(), m_disp(dw) {BAR_LEN = 40;}
    int mouseLButtonRelease(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
private:
    DisplayWidget * m_disp;
};

class DrawParallelLine :public Element
{
public:
	DrawParallelLine(void);
    ~DrawParallelLine(void) {}
    void build(QPointF p1, QPointF p2, QPointF p3);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getLength() {return m_distance;}
private:
    QPointF m_line1_start;
    QPointF m_line1_end;
    QPointF m_line2_start;
    QPointF m_line2_end;

	double m_length;//标尺的长度
	double m_distance;// 平行线间距
	double m_cos_theta;
	double m_sin_theta;

private: 
    void setStartPoint(QPointF point);
    void setEndPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setSecondLine(QPointF point);
    void setTempSecondLine(QPointF point);
	void computeLengthSlope(void);
	void computeDist(void); // 得到线段间的距离

};

//DrawRCircle 给定圆心和半径
class DrawRCircle :public Element
{
public:
    DrawRCircle(void);
    ~DrawRCircle(void){}
    void build(QPointF center, double radius);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getDiameter() {return m_radius * 2;}
private:
    QPointF m_centre;
    double m_radius;

private:
    void setCentre(QPointF point);
    void setRadius(double r);
    void setTempRadius(double r);
};

class DrawLCircle :public Element
{
public:
    DrawLCircle(void);
    ~DrawLCircle(void);
    void build(QPointF p1, QPointF p2);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getDiameter() {return m_radius * 2;}
private:
    QPointF m_start;
    QPointF m_end;
    QRect m_box;
    QPointF m_centre;
    double m_radius;

private:
    void setStartPoint(QPointF start);
    void setEndPoint(QPointF end);
    void setTempEndPoint(QPointF end);
};

class DrawRect :public Element
{
public:
    DrawRect(void);
    ~DrawRect(void);
    void build(QPointF start, QPointF end);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
private:
    QPointF m_start;
    QPointF m_end;
    QRectF m_rect;
    double m_area;

private:
    void setStartPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setEndPoint(QPointF point);
};

class DrawCorner :public Element
{
public:
    DrawCorner(void);
    ~DrawCorner(void);
    void build(QPointF start, QPointF second, QPointF end);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
private:
    QPointF m_points[3];
    AngleMeasure m_am;

private:
    void setStartPoint(QPointF start);
    void setSecondPoint(QPointF second);
    void setEndPoint(QPointF end);
    void computeAngle(void);
};


class DrawLCorner:public Element
{
public:
    DrawLCorner(void);
    ~DrawLCorner(void);
    void setStartPoint(QPointF point);
    void setEndPoint(QPointF point);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF /*point*/) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
private:
    QPointF m_line1_start; // 开始点
    QPointF m_line1_end;   // 结束点
    QPointF m_line2_start; // 开始点
    QPointF m_line2_end;   // 结束点

    double m_length;//标尺的长度
//	double m_slope;//标尺的斜率
    double m_cos_theta;
    double m_sin_theta;

private:
    void compute(void);
    void computeAngle();
    // 得到线段的长度
    void computeLength(void);
};

/**
 * @brief The DrawArc class 三点测量圆弧，得到圆弧的圆心、半径、和弧度
 */
class DrawArc :public Element
{
public:
    DrawArc(void);
    ~DrawArc(void);
    void build(QPoint p1,QPoint p2,QPoint p3); // 直接用3个点来构造圆弧
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point)  Q_DECL_OVERRIDE{Q_UNUSED(point);return 0;}
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getDiameter() {return m_radius * 2;}
private:
    QPointF m_points[3];
    QPoint m_centre;
    double m_radius;
    CircleMeasure m_circleMeasure;

private:
    void setStartPoint(QPoint start);
    void setEndPoint(QPoint end);
    void setTempEndPoint(QPoint end);
    void compute(void);
    virtual void computeBox();
};

class DrawPCIRCLE:public Element
{
public:
    DrawPCIRCLE(void);
    ~DrawPCIRCLE(void);
    void build(QPointF p1,QPointF p2,QPointF p3);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseRButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF ) Q_DECL_OVERRIDE {return 0;}
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getDiameter() {return m_radius * 2;}

private:
    QPointF m_start;
    QPointF m_middle;
    QPointF m_end;
    QPointF m_centre;
    double m_radius;

    void compute();
};

/**
 * @brief The DrawCircle2Circle class 测量两个圆的圆心间距
 */
class DrawCircle2Circle:public Element
{
public:
    DrawCircle2Circle(void);
    ~DrawCircle2Circle(void);
    void build(QPointF p[3], QPointF q[3]);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF ) Q_DECL_OVERRIDE {return 0;}
    void draw( QPainter &painter ) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getDiameter(int i) {return m_radius[i] * 2;}

private:
    QPointF m_points[6];
    int m_count; // 辅助变量，记录当前是第几个点
    QPointF m_centre[2];
    double m_radius[2];
    double m_detX; // 圆心间的 X 间距
    double m_detY; // 圆心间的 Y 间距
    double m_distance; // 圆心间距
    double m_minDistance; // 两个圆的最小距离
    CircleMeasure m_circleMeasure[2];
    void computeCircle1();
    void computeCircle2();
    void compute();
};

class DrawDots2Line:public Element
{
public:
    DrawDots2Line(void);
    ~DrawDots2Line(void){}
    void build(QPointF p1, QPointF p2, QVector<QPointF> points);
    int mouseLButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseRButtonPress(QPointF point) Q_DECL_OVERRIDE;
    int mouseLButtonRelease(QPointF point) Q_DECL_OVERRIDE;
    int mouseMove(QPointF point) Q_DECL_OVERRIDE;
    void draw( QPainter &painter) Q_DECL_OVERRIDE; //画方法
    void updateText(void) Q_DECL_OVERRIDE;
    double getLength() {return m_distance;}

private:
    QPointF m_line_start;
    QPointF m_line_end;
    double m_distance;// 点与线间距
    QVector<QString> m_texts;
    QVector<QRect> m_textBoxs;
    QVector<QPointF> m_dots_start;
    QVector<QPointF> m_dots_end;
    QPointF m_tempEnd;
//    double m_length;//标尺的长度，以像素为单位
private:

    void setStartPoint(QPointF point);
    void setTempEndPoint(QPointF point);
    void setEndPoint(QPointF point);

    void setStartDot(QPointF point);
    void setMidDot(QPointF point);
    void setTempEndDot(QPointF point);
    void setEndDot(QPointF point);
    void computeDist(void);
    void computeEndDot(void);
};

} //namespace Qly
#endif
